package ar.edu.utn.frba.disenio.model;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.uqbar.commons.utils.Observable;

import ar.edu.utn.frba.disenio.model.exceptions.ReservarNoDisponibleParaUsuarioException;
import ar.edu.utn.frba.disenio.model.exceptions.YaLoReservoElMismoException;

@Observable
public class Asiento {
	protected String codigoVuelo;
	protected int numeroDeAsiento;
	protected Ubicacion ubicacion;
	protected BigDecimal precioBase;
	protected Aerolinea aerolinea;
	protected Categoria categoria;
	protected Lugar origen;
	protected Lugar destino;
	protected Estado estado;

	protected Usuario usuarioQueReservo = null;
	protected Usuario comprador = null;
	protected List<Usuario> usuariosQueSobrereservaron = new ArrayList<Usuario>();
	
	public Asiento(String codigoVuelo, int codigoAsiento,
			Categoria categoria, Ubicacion ubicacion, BigDecimal precioBase,
			Aerolinea aerolinea) {
		this.codigoVuelo = codigoVuelo;
		this.numeroDeAsiento = codigoAsiento;
		this.categoria = categoria;
		this.ubicacion = ubicacion;
		this.precioBase = precioBase;
		this.aerolinea = aerolinea;
		this.estado = new Disponible();
	}

	public boolean esSuperOferta(){
		
		boolean esClaseEjecutivaYPrecioMenorA4000 = this.categoria.esEjecutiva() && this.getPrecioConAdicionalAerolinea().compareTo(new BigDecimal(4000))==-1;
		boolean esClasePrimeraYPrecioMenorA8000 = this.categoria.esPrimera() && this.getPrecioConAdicionalAerolinea().compareTo(new BigDecimal(8000))==-1;
		return esClasePrimeraYPrecioMenorA8000 || esClaseEjecutivaYPrecioMenorA4000;
	}

	public boolean esDeCategoria(List<Categoria> categorias) {
		for (Categoria categoria: categorias){
			if (this.getCategoria().esIgualA(categoria)) {
				return true;
			}
		}
		return false;
	}
	
	public void comprar(Usuario unUsuario){
		this.getAerolinea().comprar(this, unUsuario);
		this.setComprado(unUsuario);
		unUsuario.registrarCompra(this);
		Vuelo.incrementarPopularidad(this.getCodigoVuelo());
	}

	public void reservar(Usuario unUsuario){
		if (!unUsuario.esEstandar()) throw new ReservarNoDisponibleParaUsuarioException();
		if ( this.getEstado().estaReservado() ){
			this.sobreReservar(unUsuario);
		} else {
			this.getAerolinea().reservar(this, unUsuario);
			this.setReservado(unUsuario);
		}
	}

	public void transferirReserva(){
		if(!this.getUsuariosQueSobrereservaron().isEmpty()){
			Usuario nuevoUsuario = this.getUsuariosQueSobrereservaron().get(0);
			this.getUsuariosQueSobrereservaron().remove(0);
			this.setReservante(nuevoUsuario);
		} else {
			this.setReservante(null);
		}
	}
	
	private List<Usuario> getUsuariosQueSobrereservaron() {
		return usuariosQueSobrereservaron;
	}
	
	public boolean precioBaseEntre(BigDecimal precioMinimo, BigDecimal precioMaximo) {
		return this.precioBaseMayorIgual(precioMinimo) && this.precioBaseMenorIgual(precioMaximo);
	}

	private boolean precioBaseMenorIgual(BigDecimal precioMaximo) {
		return this.precioBase.compareTo(precioMaximo)  < 0;
	}

	private boolean precioBaseMayorIgual(BigDecimal precio) {
		
		return this.precioBase.compareTo(precio) > 0;
	}

	public Usuario getUsuarioQueReservo() {
		return this.usuarioQueReservo;
	}

	public void sobreReservar(Usuario unUsuario) {
		if (this.getUsuarioQueReservo().esElMismoUsuario(unUsuario) || 
				this.getUsuariosQueSobrereservaron().contains(unUsuario)) {
			throw new YaLoReservoElMismoException(); 
		} else {
			this.getUsuariosQueSobrereservaron().add(unUsuario);
		}		
	}
	
	private void setReservado(Usuario unUsuario) {
		this.setReservante(unUsuario);
		this.setEstado(new Reservado());
	}
	
	private void setComprado(Usuario unUsuario) {
		this.setComprador(unUsuario);
		this.quitarSobrereservas();	
		this.setEstado(new Comprado());
	}
	
	public String getCodigoVuelo() {
		return codigoVuelo;
	}

	public Lugar getOrigen() {
		return origen;
	}

	public Lugar getDestino() {
		return destino;
	}
	
	public Usuario getReserva(){
		return this.usuarioQueReservo;
	}
	
	public List<Usuario> getSobrereservas(){
		return this.getUsuariosQueSobrereservaron();
	}
	
	public Aerolinea getAerolinea() {
		return aerolinea;
	}
	
	public String getCodigoDeVuelo() {
		return codigoVuelo;
	}
	
	public int getNumeroDeAsiento() {
		return numeroDeAsiento;
	}

	public Categoria getClase() {
		return categoria;
	}

	public Ubicacion getUbicacion() {
		return ubicacion;
	}
	
	public BigDecimal getPrecio(Usuario unUsuario) {
		return getPrecioConAdicionalAerolinea().add(unUsuario.adicional());
	}
	
	public BigDecimal getPrecioConAdicionalAerolinea() {
		return precioBase.add(this.aerolinea.adicional(precioBase));
	}

	public BigDecimal getPrecioBase() {
		return this.precioBase;
	}

	public Categoria getCategoria() {
		return this.categoria;
	}
	
	public Estado getEstado(){
		return this.estado;
	}
	
	private void setEstado(Estado unEstado){
		this.estado = unEstado;
	}
	
	private void setReservante(Usuario unUsuario){
		this.usuarioQueReservo = unUsuario;
	}
	
	private void setComprador(Usuario unUsuario) {
		this.comprador = unUsuario;
	}
	
	public void agregarUsuarioQueReservo(Usuario unUsuario){
		this.usuarioQueReservo = unUsuario;
	}
	
	private void quitarSobrereservas() {
		this.getSobrereservas().clear();
	}
	
	public Usuario getComprador(){
		return this.comprador;
	}
}
